package com.smartao.core.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.Assert;

import com.smartao.core.security.exception.UserNotFoundException;
import com.smartao.core.security.exception.WrongPasswordException;

/**
 * 登录验证
 * @author Ricky
 */
public class DaoAuthenticationProvider implements AuthenticationProvider {

	private final Logger logger = LoggerFactory.getLogger(DaoAuthenticationProvider.class);

	private PasswordEncoder passwordEncoder;
	private AccountManager accountManager;

	/**
	 * 携带数据为 {@link AuthenticationToken}
	 */
	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		Assert.isInstanceOf(AuthenticationToken.class, authentication,"Only AuthenticationToken is supported");
		String account = null;
		
		if (authentication.getPrincipal() instanceof SmartaoUser) {
			account = ((SmartaoUser) authentication.getPrincipal()).getAccount();
        }
        else {
        	account = authentication.getPrincipal().toString();
        }

		SmartaoUser user = accountManager.findUserByAccount(account);
		if(user == null){
			String message = "User '" + authentication.getName() + "' not found";
			logger.error(message);
			throw new UserNotFoundException(message);
		}
		
		additionalAuthenticationChecks(user, (AuthenticationToken) authentication);

		return createSuccessAuthentication(authentication,user);
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return (AuthenticationToken.class.isAssignableFrom(authentication));
	}

	/**
	 * 用户密码验证
	 */
	protected void additionalAuthenticationChecks(SmartaoUser user, AuthenticationToken authentication)
			throws AuthenticationException {

		if (authentication.getCredentials() == null) {
			logger.info("Authentication failed: no credentials provided");
			throw new WrongPasswordException("密码错误!");
		}

		String presentedPassword = authentication.getCredentials().toString();

		boolean isPasswordValid = getPasswordEncoder().isPasswordValid(user.getPassword(), presentedPassword, null);

		if (!isPasswordValid) {
			logger.info("Authentication failed: password does not match stored value");
			throw new WrongPasswordException("密码错误!");
		}
	}

	/**
	 * 此处返回的Authentication中携带的principal对象为SmartaoUser
	 */
	protected Authentication createSuccessAuthentication(Authentication authentication, SmartaoUser user) {
		Object credentials = authentication.getCredentials();
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		authorities.add(new SimpleGrantedAuthority(SmartaoRole.ROLE_USER));
		//从数据库获取用户角色
		Collection<String> userAuthorities = user.getAuthorities();
		for(String userAuthority:userAuthorities){
			authorities.add(new SimpleGrantedAuthority(userAuthority));
		}
		AuthenticationToken result = new AuthenticationToken(user, credentials, authorities);
		result.setDetails(authentication.getDetails());
		return result;
	}

	public PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	@Autowired
	public void setAccountManager(AccountManager accountManager) {
		this.accountManager = accountManager;
	}

}
